package com.hup.winHolderService.service;

import com.hup.utils.commons.hardware.HRobotJni;
import com.hup.winHolderService.constant.MouseButton;
import com.hup.winHolderService.framework.exception.AppServerException;
import com.hup.winHolderService.model.action.ButtonActionReq;
import com.hup.winHolderService.model.action.MouseActionReq;
import com.hup.winHolderService.model.action.ScrollActionReq;
import com.hup.winHolderService.service.mouseMove.MouseMoveHandler;
import com.hup.winHolderService.service.mouseMove.MouseMoveHandler2;
import com.hup.winHolderService.ws.WsClient;
import com.hup.winHolderService.ws.WsClientHandler;
import com.hup.winHolderService.ws.handler.WsRequestData;
import com.hup.winHolderService.ws.handler.WsRequestMethod;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * 执行[鼠键]等操作
 *
 * @author hugan
 * @date 2023/10/4
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MockActionService {

    private final Set<Integer> activeKey = Collections.synchronizedSet(new HashSet<>());
    private final Set<Integer> activeMouse = Collections.synchronizedSet(new HashSet<>());

    //private final MouseMoveHandler mouseMoveHandler = new MouseMoveHandler1();
    private final MouseMoveHandler mouseMoveHandler = new MouseMoveHandler2();
    private Robot robot;

    @Setter
    private WsClientHandler clientHandler;

    @PostConstruct
    public void init() {
        try {
            robot = new Robot();
        } catch (AWTException e) {
            throw new AppServerException("robot初始化异常");
        }
    }

    @PreDestroy
    public void doDestroy() {
        releaseActionFunction();
    }

    @WsRequestMethod("mouseAction")
    public void mouseAction(@WsRequestData MouseActionReq req, WsClient client) {
        //log.info("req={}", req);
        switch (req.getAction()) {
            case MouseActionReq.ACTION_MOVE_START:
                HRobotJni.showMouse();
                mouseMoveHandler.onMoveStart(req);
                return;
            case MouseActionReq.ACTION_MOVE:
                mouseMoveHandler.onMove(req);
                return;
            case MouseActionReq.ACTION_PRESS:
                robot.mousePress(InputEvent.BUTTON1_MASK);
                activeMouse.add(InputEvent.BUTTON1_MASK);
                return;
            case MouseActionReq.ACTION_UP:
                robot.mouseRelease(InputEvent.BUTTON1_MASK);
                activeMouse.remove(InputEvent.BUTTON1_MASK);
                return;
            case MouseActionReq.ACTION_CLICK:
                robot.mousePress(InputEvent.BUTTON1_MASK);
                robot.delay(100);//简单测试结果,实体设备间隔:触控板[112,120],鼠标[75,90]
                robot.mouseRelease(InputEvent.BUTTON1_MASK);
        }
    }

    @WsRequestMethod("scrollAction")
    public void scrollAction(@WsRequestData ScrollActionReq req, WsClient client) {
        //log.info("req={}", req);
        HRobotJni.mouseWheel(
                req.getIsAdd() ? 1 : -1,
                !req.getIsVertical()
        );
    }

    @WsRequestMethod("buttonAction")
    public void buttonAction(@WsRequestData ButtonActionReq req, WsClient client) {
        //log.info("req={}", req);
        if (ButtonActionReq.TYPE_KEYBOARD == req.getType()) {
            handleKeyboardAction(req);
        } else if (ButtonActionReq.TYPE_MOUSE == req.getType()) {
            int button = MouseButton.getButton(req.getKeyCode());
            if (ButtonActionReq.ACTION_PRESS == req.getAction()) {
                robot.mousePress(button);
                activeMouse.add(button);
            } else if (ButtonActionReq.ACTION_UP == req.getAction()) {
                robot.mouseRelease(button);
                activeMouse.remove(button);
            } else if (ButtonActionReq.ACTION_CLICK == req.getAction()) {
                robot.mousePress(button);
                robot.delay(100);
                robot.mouseRelease(button);
            }
        }
    }

    private void handleKeyboardAction(ButtonActionReq req) {
        boolean useJni = false;
        if (req.getKeyCode().startsWith(ButtonActionReq.SPECIAL_KEY_PREFIX)) {
            //使用jni触发[原始的winApi的keyCode]
            req.setKeyCode(req.getKeyCode().replace(ButtonActionReq.SPECIAL_KEY_PREFIX, ""));
            useJni = true;
        }
        String[] keycodeStrS = req.getKeyCode().split(",");
        for (String keycodeStr : keycodeStrS) {
            if (StringUtils.isBlank(keycodeStr)) continue;
            int keycode = Integer.parseInt(keycodeStr.substring(2), 16);
            //log.info("action={}, key={}", req.getAction(), KeyEvent.getKeyText(keycode));

            if (useJni) {
                if (ButtonActionReq.ACTION_PRESS == req.getAction()
                        || ButtonActionReq.ACTION_CLICK == req.getAction()) {
                    //只在[按下(触屏), click(pc浏览器)]时触发[click按键]
                    HRobotJni.clickKey(keycode);
                }
            } else {
                if (ButtonActionReq.ACTION_PRESS == req.getAction()) {
                    robot.keyPress(keycode);
                    activeKey.add(keycode);
                } else if (ButtonActionReq.ACTION_UP == req.getAction()) {
                    robot.keyRelease(keycode);
                    activeKey.remove(keycode);
                } else if (ButtonActionReq.ACTION_CLICK == req.getAction()) {
                    robot.keyPress(keycode);
                    robot.delay(100);
                    robot.keyRelease(keycode);
                }
            }
        }
    }

    @WsRequestMethod(value = "getKeyboardState", noneRequestData = true)
    public void getKeyboardState(WsClient client) {
        byte state = HRobotJni.getKeyboardState();
        //log.info("state={}", state);
        clientHandler.sendTo(client, "onKeyboardState", state);
    }

    /**
     * 释放所有已激活的功能
     */
    public void releaseActionFunction() {
        log.info("activeKey={}, activeMouse={}", activeKey.size(), activeMouse.size());
        if (!activeKey.isEmpty()) {
            activeKey.forEach(keyCode -> robot.keyRelease(keyCode));
            activeKey.clear();
        }
        if (!activeMouse.isEmpty()) {
            activeMouse.forEach(keyCode -> robot.mouseRelease(keyCode));
            activeMouse.clear();
        }
    }

}
